import time
import threading
import pygame
import serial
import numpy as np
from BrainLinkParser import BrainLinkParser

# ============== 配置 ==============
COM_PORT = "COM5"          # ←←← 必须修改！改成你 Brainlink Pro 的实际串口号
BAUDRATE = 115200

# 初始化 pygame 音频
pygame.mixer.init(frequency=44100, size=-16, channels=1, buffer=512)

# ============== 生成简单钢琴音函数 ==============
def play_note(freq=523, duration=0.25, volume=0.6):
    """生成正弦波音符（模拟钢琴）"""
    sample_rate = 44100
    t = np.linspace(0, duration, int(sample_rate * duration), False)
    tone = np.sin(freq * t * 2 * np.pi)
    
    # 简单包络，让声音更自然（不那么刺耳）
    envelope = np.exp(-3 * t)
    audio = tone * envelope * volume * 32767
    
    sound = pygame.sndarray.make_sound(audio.astype(np.int16))
    sound.play()

# ============== Brainlink 数据回调 ==============
def on_eeg(data):
    attention = getattr(data, 'attention', 0)
    meditation = getattr(data, 'meditation', 0)
    blink = getattr(data, 'blinkStrength', getattr(data, 'blink', 0))

    print(f"专注度: {attention:3d} | 放松度: {meditation:3d} | 眨眼: {blink:3d}")

    # 脑电波 → 钢琴映射（可自行调整阈值和音高）
    if attention > 65:                    # 专注 → 较高、较明亮的音
        freq = 523 + (attention - 65) * 10   # 从 C5 开始向上
        play_note(freq, duration=0.18, volume=0.75)

    elif meditation > 55:                 # 放松 → 较低、较柔和的长音
        freq = 330 + (meditation - 55) * 4   # 从 E4 附近开始
        play_note(freq, duration=0.45, volume=0.65)

    if blink > 70:                        # 眨眼 → 高音强调
        play_note(784, duration=0.12, volume=0.9)   # G5

# ============== 创建 Parser ==============
parser = BrainLinkParser(eeg_callback=on_eeg)

# ============== 串口读取线程 ==============
def read_serial():
    try:
        ser = serial.Serial(COM_PORT, BAUDRATE, timeout=0.5)
        print(f"✅ 串口 {COM_PORT} 打开成功！")
        print("🎹 请戴上 Brainlink Pro，用意念控制钢琴吧！")
        print("   专注 → 高音活泼    放松 → 低音柔和    眨眼 → 强音")

        while True:
            if ser.in_waiting > 0:
                msg = ser.read(ser.in_waiting)
                if msg:
                    parser.parse(msg)       # 关键：把数据传给 Parser
            time.sleep(0.001)
    except serial.SerialException as e:
        print(f"❌ 串口打开失败: {e}")
        print("提示：")
        print("1. 在设备管理器中确认 Brainlink Pro 的 COM 口号")
        print("2. 先用官方 App 测试是否能连上并看到数据")
        print("3. 关闭其他占用该串口的程序")
    except Exception as e:
        print(f"读取出错: {e}")

# 启动线程
threading.Thread(target=read_serial, daemon=True).start()

print("程序已启动，按 Ctrl + C 退出")

try:
    while True:
        time.sleep(0.1)
except KeyboardInterrupt:
    pygame.mixer.quit()
    print("\n🎹 演奏已停止")